﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using EpsiRisk.DonneesPlateau;
using EpsiRisk.AffichageJeu;
using System.Xml.Serialization;
using System.Threading;

namespace EpsiRisk.MoteurJeu
{
    public class ClassInstanciedEtatPartie
    {
        [XmlElement]
        int indexJoueurCourant
        {
            get { return ClassEtatPartie.indexJoueurCourant; }
            set { ClassEtatPartie.indexJoueurCourant = value; }
        }

        [XmlElement]
        int phase
        {
            get { return ClassEtatPartie.phase; }
            set { ClassEtatPartie.phase = value; }
        }

        [XmlElement]
        int renforts
        {
            get { return ClassEtatPartie.renforts; }
            set { ClassEtatPartie.renforts = value; }
        }

        [XmlElement]
        bool modeMissions
        {
            get { return ClassEtatPartie.modeMissions; }
            set { ClassEtatPartie.modeMissions = value; }
        }
    }

    public static class ClassEtatPartie
    {
        public static XmlSerializer serializer = new XmlSerializer((new ClassInstanciedEtatPartie()).GetType());

        public static int indexJoueurCourant;


        /// <summary>
        /// phase courante:
        /// O -> renforts
        /// 1 -> attaque
        /// 2 -> deplacement
        /// 3 -> affectation initiale
        /// </summary>
        public static int phase;


        public static int renforts;


        public static bool partieEnCours = false;


        public static bool modeMissions;


        private static ClassSousTerritoire sTS;


        private static ClassSousTerritoire sTSb;


        public static ClassSousTerritoire sousTerritoireSelectionne
        {
            get { return sTS; }
            set
            {
                sTS = value;
                if (value == null)
                {
                    ClassDonneesGlobales.zoneJeu.calque = null;
                }
                else
                {
                    ClassDonneesGlobales.zoneJeu.calque = value.calque;
                    Console.WriteLine("Territoire Sélectionné : " + sTS.Nom);
                }
            }
        }

        public static ClassSousTerritoire sousTerritoireSelectionneBis
        {
            get { return sTSb; }
            set
            {
                sTSb = value;
                if (value == null)
                {
                    ClassDonneesGlobales.zoneJeu.calqueb = null;
                }
                else
                {
                    ClassDonneesGlobales.zoneJeu.calqueb = value.calque;
                    Console.WriteLine("Territoire Sélectionné bis : " + sTSb.Nom);
                }
            }
        }

        public static string phaseString()
        {
            switch (phase)
            {
                case 0:
                    return "Phase de renforts";
                case 1:
                    return "Phase d'attaque";
                case 2:
                    return "Phase de mouvement";
                case 3:
                    return "Placement initial";
                case 4:
                    return "Partie terminée";
                default:
                    return null;
            }
        }

        public static void demarrerPartie()
        {
            ClassDonneesGlobales.plateauCourant.viderSoldats();
            if (partieEnCours)
            {
                switch (phase)
                {
                    case 0:
                        ClassZoneJeu.ClicSurSousTerritoireEvent -= ClassZoneJeu_ClicSurSousTerritoireEvent;
                        break;
                    case 1:
                        ClassZoneJeu.ClicSurSousTerritoireEvent -= new EventHandler(ClassZoneJeu_ClicSurSousTerritoireEvent2);
                        break;
                    case 2:
                        ClassZoneJeu.ClicSurSousTerritoireEvent -= new EventHandler(ClassZoneJeu_ClicSurSousTerritoireEvent3);
                        break;
                    case 3:
                        ClassZoneJeu.ClicSurSousTerritoireEvent -= ClassZoneJeu_ClicSurSousTerritoireEvent;
                        break;
                    case 4:                        
                        break;
                    default:
                        throw new NotImplementedException();
                }
            }
            phase = 3;
            modeMissions = false;/*
            if (ClassJoueur.listeJoueurs.Count == 0)
            {
                ClassJoueur joueur1 = new ClassJoueur("Red");
                ClassJoueur joueur2 = new ClassJoueur("Blue");
                ClassJoueur joueur3 = new ClassJoueur("Green");
                ClassJoueur joueur4 = new ClassJoueur("Yellow");
            }*/
            indexJoueurCourant = 0;
            repartitionPays();
            initialiserPhaseRenforts();
            renforts = 15;
            ClassZoneJeu.ClicSurSousTerritoireEvent += new EventHandler(ClassZoneJeu_ClicSurSousTerritoireEvent);
            ClassDonneesGlobales.zoneOverlayMessage.PopText("Tour du joueur " + (indexJoueurCourant + 1));
            partieEnCours = true;
            if (!joueurCourant().estHumain)
            {
                ClassMoteurIA.threadmoteurIA = new Thread(ClassMoteurIA.JoueurMachine);
                ClassMoteurIA.threadmoteurIA.Start();
            }
        }

        public static void terminerPhase()
        {
            switch (phase)
            {
                case 0:
                    if (renforts != 0)
                    {
                        ClassDonneesGlobales.zoneOverlayMessage.PopText("Vous devez affecter tous les renforts");
                    }
                    else
                    {
                        ClassPhaseAttaque.initialisePhaseAttaque();
                        phase = 1;
                        ClassDonneesGlobales.zoneContextuelle = ClassDonneesGlobales.zoneSelectionAttaquant;//zonelancementdes
                        if (!joueurCourant().estHumain)
                        {
                            ClassMoteurIA.threadmoteurIA = new Thread(ClassMoteurIA.JoueurMachine);
                            ClassMoteurIA.threadmoteurIA.Start();
                        }
                        ClassZoneJeu.ClicSurSousTerritoireEvent -= ClassZoneJeu_ClicSurSousTerritoireEvent;
                        ClassZoneJeu.ClicSurSousTerritoireEvent += new EventHandler(ClassZoneJeu_ClicSurSousTerritoireEvent2);
                    }
                    break;
                case 1:
                    phase = 2;
                    sousTerritoireSelectionne = null;
                    sousTerritoireSelectionneBis = null;
                    ClassDonneesGlobales.zoneContextuelle = ClassDonneesGlobales.zoneDeplacement;
                    if (!joueurCourant().estHumain)
                    {
                        ClassMoteurIA.threadmoteurIA = new Thread(ClassMoteurIA.JoueurMachine);
                        ClassMoteurIA.threadmoteurIA.Start();
                    }
                    ClassZoneJeu.ClicSurSousTerritoireEvent -= new EventHandler(ClassZoneJeu_ClicSurSousTerritoireEvent2);
                    ClassZoneJeu.ClicSurSousTerritoireEvent += new EventHandler(ClassZoneJeu_ClicSurSousTerritoireEvent3);

                    break;
                case 2:
                    passerAuJoueurSuivant();
                    phase = 0;
                    initialiserPhaseRenforts();
                    renforts = calculerRenforts(joueurCourant());
                    if (!joueurCourant().estHumain)
                    {
                        ClassMoteurIA.threadmoteurIA = new Thread(ClassMoteurIA.JoueurMachine);
                        ClassMoteurIA.threadmoteurIA.Start();
                    }
                    ClassZoneJeu.ClicSurSousTerritoireEvent -= new EventHandler(ClassZoneJeu_ClicSurSousTerritoireEvent3);
                    ClassZoneJeu.ClicSurSousTerritoireEvent += new EventHandler(ClassZoneJeu_ClicSurSousTerritoireEvent);

                    break;
                case 3:
                    if (renforts != 0)
                    {
                        ClassDonneesGlobales.zoneOverlayMessage.PopText("Vous devez affecter tous les renforts");
                    }
                    else
                    {
                        if (indexJoueurCourant == ClassJoueur.listeJoueurs.Count - 1)
                        {
                            passerAuJoueurSuivant();
                            phase = 0;
                            initialiserPhaseRenforts();
                            renforts = calculerRenforts(joueurCourant());
                        }
                        else
                        {
                            passerAuJoueurSuivant();
                            phase = 3;
                            initialiserPhaseRenforts();
                            renforts = 15;
                        }
                        ClassDonneesGlobales.zoneOverlayMessage.PopText("Tour du joueur " + (indexJoueurCourant + 1));
                    }
                    if (!joueurCourant().estHumain)
                    {
                        ClassMoteurIA.threadmoteurIA = new Thread(ClassMoteurIA.JoueurMachine);
                        ClassMoteurIA.threadmoteurIA.Start();
                    }
                    break;
                case 4:
                    //PARTIE TERMINEE
                    terminerPartie(joueurCourant());
                    break;
                default:
                    throw new NotImplementedException();
            }
        }

        public static void initialiserPhaseRenforts()
        {
            sousTerritoireSelectionne = null;
            sousTerritoireSelectionneBis = null;
            ClassDonneesGlobales.zoneContextuelle = ClassDonneesGlobales.zoneAffectationRenforts;
        }

        /// <summary>
        /// gestion du clic sur territoire en phase renforts
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        static void ClassZoneJeu_ClicSurSousTerritoireEvent(object sender, EventArgs e)
        {
            if (sousTerritoireSelectionne == (ClassSousTerritoire)sender)//cas de désélection
            {
                sousTerritoireSelectionne = null;
            }
            else
            {
                if (((ClassSousTerritoire)sender).Proprietaire != joueurCourant())
                {
                    sousTerritoireSelectionne = null;
                    ClassDonneesGlobales.zoneOverlayMessage.PopText("Ce " + ClassDonneesGlobales.plateauCourant.AliasSousTerritoire + " ne vous appartient pas !");
                    Console.WriteLine("Erreur : " + ((ClassSousTerritoire)sender).Nom + " n'appartient pas au joueur courant !");
                }
                else
                {
                    sousTerritoireSelectionne = (ClassSousTerritoire)sender;
                }

            }
        }

        /// <summary>
        /// gestion du clic sur territoire en phase de déplacement
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        static void ClassZoneJeu_ClicSurSousTerritoireEvent3(object sender, EventArgs e)
        {
            ClassPhaseDeplacement.ClicSousTerritoire((ClassSousTerritoire)sender);
        }

        /// <summary>
        /// gestion du clic sur territoire en phase d'attaque
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        static void ClassZoneJeu_ClicSurSousTerritoireEvent2(object sender, EventArgs e)
        {
            ClassPhaseAttaque.ClicSousTerritoire((ClassSousTerritoire)sender);

        }

        /// <summary>
        /// joueur dont c'est le tour
        /// </summary>
        public static ClassJoueur joueurCourant()
        {
            if (indexJoueurCourant < ClassJoueur.listeJoueurs.Count)
            {
                return ClassJoueur.listeJoueurs[indexJoueurCourant];
            }
            else
            {
                return null;
            }
        }

        /// <summary>
        ///retourne le joueur suivant
        /// </summary>
        /// <returns></returns>
        public static ClassJoueur joueurSuivant()
        {
            if (indexJoueurCourant + 1 == ClassJoueur.listeJoueurs.Count)
            {
                return ClassJoueur.listeJoueurs[0];
            }
            else
            {
                return ClassJoueur.listeJoueurs[indexJoueurCourant + 1];
            }
        }

        /// <summary>
        ///passe au joueur suivant 
        /// </summary>
        public static void passerAuJoueurSuivant()
        {
            if (indexJoueurCourant + 1 == ClassJoueur.listeJoueurs.Count)
            {
                indexJoueurCourant = 0;
            }
            else
            {
                indexJoueurCourant++;
            }
        }

        /// <summary>
        /// calcule les renforts d'un joueur
        /// </summary>
        /// <param name="j">joueur dont  on calcule les renforts</param>
        /// <returns></returns>
        public static int calculerRenforts(ClassJoueur j)
        {
            int res = 0;
            res = res + ClassDonneesGlobales.plateauCourant.nombreSousTerritoiresPossedes(j) / 3;
            res = res + calculerBonus(j);

            if (res < 3)
            {
                return 3;//valeur par default
            }
            else
            {
                return res;
            }
        }


        /// <summary>
        /// calcule les renforts  bonus d'un joueur
        /// </summary>
        /// <param name="j"></param>
        /// <returns></returns>
        private static int calculerBonus(ClassJoueur j)
        {
            int res = 0;
            foreach (ClassTerritoire t in ClassDonneesGlobales.plateauCourant.ListeTerritoires)
            {
                if (t.possedeTerritoireComplet(j))
                {
                    res = res + t.ValeurRenforts;
                }
            }
            return res;
        }

        /// <summary>
        /// affecter n renforts au territoire selectionné
        /// </summary>
        /// <param name="nb"></param>
        internal static void affecterRenfort(int nb)
        {
            if (ClassEtatPartie.sousTerritoireSelectionne == null)
            {
                Console.WriteLine("Pas de Sous territoire selectionné pour affecter les renforts");
                ClassDonneesGlobales.zoneOverlayMessage.PopText("Pas de " + ClassDonneesGlobales.plateauCourant.AliasSousTerritoire + " selectionne");
            }
            else
            {
                if (renforts - nb >= 0)
                {
                    for (int i = 0; i < nb; i++)
                    {
                        ClassEtatPartie.sousTerritoireSelectionne.ajouterSoldat();
                        ClassEtatPartie.renforts--;
                    }
                    Console.WriteLine(nb + "renforts affectés en " + sousTerritoireSelectionne.Nom);
                }
                else { ClassDonneesGlobales.zoneOverlayMessage.PopText("Pas assez de renforts disponibles"); }
            }
        }

        /// <summary>
        /// rends true si la partie est finie
        /// </summary>
        /// <returns></returns>
        public static bool victoireDefaite()
        {
            if (modeMissions)
            {
                if (joueurCourant().mission.accompli(joueurCourant()))
                {
                    ClassDonneesGlobales.zoneOverlayMessage.PopText(joueurCourant().Nom + " a reussi sa mission!");
                    return true;
                }
            }
            else
            {
                if (joueurCourant().nbTerritoires == 42)
                {
                    ClassDonneesGlobales.zoneOverlayMessage.PopText(joueurCourant().Nom + " a conquis le monde!");
                    return true;
                }
            }
            int i = 0;
            while (i < ClassJoueur.listeJoueurs.Count)
            {
                if (ClassJoueur.listeJoueurs[i].nbTerritoires == 0)
                {
                    ClassDonneesGlobales.zoneOverlayMessage.PopText(ClassJoueur.listeJoueurs[i].Nom + " a perdu");
                    ClassJoueur.listeJoueurs.RemoveAt(i);
                }
                else
                {
                    i++;
                }
            }
            return false;
        }

        /// <summary>
        /// repartit les pays entre les joueurs 
        /// </summary>
        private static void repartitionPays()
        {
            Random rand = new Random();
            int nbjoueurs = ClassJoueur.listeJoueurs.Count;
            //VERSION PAR TERRITOIRE
            /*
            foreach (ClassSousTerritoire st in ClassDonneesGlobales.plateauCourant.listeSousTerritoires())
            {
                while (st.Proprietaire == null)
                {
                    ClassJoueur randJoueur = ClassJoueur.listeJoueurs[rand.Next(nbjoueurs)];//choisit ou joueur au hasard
                    if (ClassDonneesGlobales.plateauCourant.nombreSousTerritoiresPossedes(randJoueur) <= (ClassDonneesGlobales.plateauCourant.listeSousTerritoires().Count + nbjoueurs - 1) / nbjoueurs)
                    {
                        st.Proprietaire = randJoueur;
                        st.ajouterSoldat();//ajoute un soldat initial
                    }
                }
            }*/
            //VERSION PAR JOUEUR

            List<ClassSousTerritoire> SousTerritoiresAAffecter = new List<ClassSousTerritoire> { };
            foreach (ClassSousTerritoire st in ClassDonneesGlobales.plateauCourant.listeSousTerritoires())
            {
                SousTerritoiresAAffecter.Add(st);
            }
            foreach (ClassJoueur joueur in ClassJoueur.listeJoueurs)
            {
                for (int i = 0; i <= ClassDonneesGlobales.plateauCourant.listeSousTerritoires().Count / ClassJoueur.listeJoueurs.Count; i++)
                {
                    if (SousTerritoiresAAffecter.Count != 0)
                    {
                        int r = rand.Next(SousTerritoiresAAffecter.Count);
                        Console.WriteLine("r= " + r);
                        SousTerritoiresAAffecter[r].Proprietaire = joueur;
                        SousTerritoiresAAffecter[r].ajouterSoldat();//ajoute un soldat initial
                        SousTerritoiresAAffecter.RemoveAt(r);
                    }
                }
            }
        }

        public static void terminerPartie(ClassJoueur vainqueur) { }
    }
}
